/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
+const Gdk = imports.gi.Gdk;
+const Gio = imports.gi.Gio;
+const GLib = imports.gi.GLib;
+const Shell = imports.gi.Shell;
+
+const Main = imports.ui.main;
+const MessageTray = imports.ui.messageTray;
+
+const Gettext = imports.gettext.domain('gnome-shell');
+const _ = Gettext.gettext;
+
/* http://daringfireball.net/2010/07/improved_regex_for_matching_urls */
const _urlRegexp = new RegExp('\b(([a-z][\w-]+:(/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)([^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:\'".,<>?«»“”‘’]))', 'gi');
res.push({ url: match[0], pos: match.index });
return res;
}
+
+// spawn:
+// @argv: an argv array
+//
+// Runs @argv in the background, handling any errors that occur
+// when trying to start the program.
+function spawn(argv) {
+ try {
+ trySpawn(argv);
+ } catch (err) {
+ _handleSpawnError(argv[0], err);
+ }
+}
+
+// spawnCommandLine:
+// @command_line: a command line
+//
+// Runs @command_line in the background, handling any errors that
+// occur when trying to parse or start the program.
+function spawnCommandLine(command_line) {
+ try {
+ let [success, argc, argv] = GLib.shell_parse_argv(command_line);
+ trySpawn(argv);
+ } catch (err) {
+ _handleSpawnError(command_line, err);
+ }
+}
+
+// spawnDesktop:
+// @id: a desktop file ID
+//
+// Spawns the desktop file identified by @id using startup notification,
+// etc, handling any errors that occur when trying to find or start
+// the program.
+function spawnDesktop(id) {
+ try {
+ trySpawnDesktop(id);
+ } catch (err) {
+ _handleSpawnError(id, err);
+ }
+}
+
+// trySpawn:
+// @argv: an argv array
+//
+// Runs @argv in the background. If launching @argv fails,
+// this will throw an error.
+function trySpawn(argv)
+{
+ try {
+ GLib.spawn_async(null, argv, null,
+ GLib.SpawnFlags.SEARCH_PATH,
+ null, null);
+ } catch (err) {
+ // The exception from gjs contains an error string like:
+ // Error invoking GLib.spawn_command_line_async: Failed to
+ // execute child process "foo" (No such file or directory)
+ // We are only interested in the part in the parentheses. (And
+ // we can't pattern match the text, since it gets localized.)
+ err.message = err.message.replace(/.*\((.+)\)/, '$1');
+ throw err;
+ }
+}
+
+// trySpawnCommandLine:
+// @command_line: a command line
+//
+// Runs @command_line in the background. If launching @command_line
+// fails, this will throw an error.
+function trySpawnCommandLine(command_line) {
+ let success, argc, argv;
+
+ try {
+ [success, argc, argv] = GLib.shell_parse_argv(command_line);
+ } catch (err) {
+ // Replace "Error invoking GLib.shell_parse_argv: " with
+ // something nicer
+ err.message = err.message.replace(/[^:]*: /, _("Could not parse command:") + "\n");
+ throw err;
+ }
+
+ trySpawn(argv);
+}
+
+// trySpawnDesktop:
+// @id: a desktop file ID
+//
+// Spawns the desktop file identified by @id using startup notification.
+// On error, throws an exception.
+function trySpawnDesktop(id) {
+ let app;
+
+ // shell_app_system_load_from_desktop_file() will end up returning
+ // a stupid error message if the desktop file doesn't exist, but
+ // that's the only case it returns an error for, so we just
+ // substitute our own error in instead
+ try {
+ app = Shell.AppSystem.get_default().load_from_desktop_file(id + '.desktop');
+ } catch (err) {
+ throw new Error(_("No such application"));
+ }
+
+ try {
+ app.launch();
+ } catch(err) {
+ // see trySpawn
+ err.message = err.message.replace(/.*\((.+)\)/, '$1');
+ throw err;
+ }
+}
+
+function _handleSpawnError(command, err) {
+ let title = _("Execution of '%s' failed:").format(command);
+
+ let source = new MessageTray.SystemNotificationSource();
+ Main.messageTray.add(source);
+ let notification = new MessageTray.Notification(source, title, err.message);
+ notification.setTransient(true);
+ source.notify(notification);
+}
const Magnifier = imports.ui.magnifier;
const XdndHandler = imports.ui.xdndHandler;
const StatusIconDispatcher = imports.ui.statusIconDispatcher;
+const Util = imports.misc.util;
const DEFAULT_BACKGROUND_COLOR = new Clutter.Color();
DEFAULT_BACKGROUND_COLOR.from_pixel(0x2266bbff);
if (action == Meta.KeyBindingAction.COMMAND_SCREENSHOT) {
let gconf = GConf.Client.get_default();
let command = gconf.get_string('/apps/metacity/keybinding_commands/command_screenshot');
- if (command != null && command != '') {
- let [ok, len, args] = GLib.shell_parse_argv(command);
- let p = new Shell.Process({'args' : args});
- p.run();
- }
+ if (command != null && command != '')
+ Util.spawnCommandLine(command);
return true;
}
return true;
} catch (e) {
// TODO: remove this after gnome 3 release
- let p = new Shell.Process({ 'args' : ['gvfs-open', url] });
- p.run();
+ Util.spawn(['gvfs-open', url]);
return true;
}
}
const DND = imports.ui.dnd;
const Main = imports.ui.main;
const Search = imports.ui.search;
+const Util = imports.misc.util;
const NAUTILUS_PREFS_DIR = '/apps/nautilus/preferences';
const DESKTOP_IS_HOME_KEY = NAUTILUS_PREFS_DIR + '/desktop_is_home_dir';
icon_size: size });
},
function () {
- new Shell.Process({ args: ['nautilus-connect-server'] }).run();
+ Util.spawn(['nautilus-connect-server']);
});
let networkApp = null;
const Lightbox = imports.ui.lightbox;
const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
+const Util = imports.misc.util;
const MAX_FILE_DELETED_BEFORE_INVALID = 10;
try {
if (inTerminal)
command = 'gnome-terminal -x ' + input;
- let [ok, len, args] = GLib.shell_parse_argv(command);
- let p = new Shell.Process({ 'args' : args });
- p.run();
+ Util.trySpawnCommandLine(command);
} catch (e) {
// Mmmh, that failed - see if @input matches an existing file
let path = null;
global.create_app_launch_context());
} else {
this._commandError = true;
- // The exception contains an error string like:
- // Error invoking Shell.run: Failed to execute child
- // process "foo" (No such file or directory)
- // We are only interested in the actual error, so parse
- //that out.
- let m = /.+\((.+)\)/.exec(e);
- let errorStr = _("Execution of '%s' failed:").format(command) + '\n' + m[1];
+
+ let errorStr = _("Execution of '%s' failed:").format(command) + '\n' + e.message;
this._errorMessage.set_text(errorStr);
this._errorBox.show();
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
+const Util = imports.misc.util;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this.menu.addAction(_("Universal Access Settings"), function() {
- let p = new Shell.Process({ args: ['gnome-control-center','universal-access'] });
- p.run();
+ Util.spawnDesktop('gnome-universal-access-panel');
});
},
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
+const Util = imports.misc.util;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this.menu.addAction(_("Power Settings"),function() {
- GLib.spawn_command_line_async('gnome-control-center power');
+ Util.spawnDesktop('gnome-power-panel');
});
this._proxy.connect('Changed', Lang.bind(this, this._devicesChanged));
this._batteryItem.actor.reactive = true;
this._batteryItem.actor.can_focus = true;
this._batteryItem.connect('activate', function(item) {
- let p = new Shell.Process({ args: ['gnome-power-statistics', '--device', device_id] });
- p.run();
+ Util.spawn(['gnome-power-statistics', '--device', device_id]);
});
} else {
// virtual device
let item = new DeviceItem (devices[i]);
item.connect('activate', function() {
- let p = new Shell.Process({ args: ['gnome-power-statistics', '--device', device_id] });
- p.run();
+ Util.spawn(['gnome-power-statistics', '--device', device_id]);
});
this._deviceItems.push(item);
this.menu.addMenuItem(item, this._otherDevicePosition + position);
_checkError: function(error) {
if (!this._restarted && error && error.message.match(/org\.freedesktop\.DBus\.Error\.(UnknownMethod|InvalidArgs)/)) {
GLib.spawn_command_line_sync('pkill -f "^gnome-power-manager$"');
- GLib.spawn_command_line_async('gnome-power-manager');
+ Util.spawn(['gnome-power-manager']);
this._restarted = true;
}
}
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
+const Util = imports.misc.util;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this.menu.addAction(_("Sound Settings"), function() {
- let p = new Shell.Process({ args: ['gnome-control-center', 'sound'] });
- p.run();
+ Util.spawnDesktop('gnome-sound-panel');
});
this.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
+const Util = imports.misc.util;
// Adapted from gdm/gui/user-switch-applet/applet.c
//
this.actor.set_child(box);
this._gdm = Gdm.UserManager.ref_default();
- this._gdm.queue_load()
+ this._gdm.queue_load();
this._user = this._gdm.get_user(GLib.get_user_name());
this._presence = new GnomeSession.Presence();
_onMyAccountActivate: function() {
Main.overview.hide();
- this._spawn(['gnome-control-center', 'user-accounts']);
+ Util.spawnDesktop('gnome-user-accounts-panel');
},
_onPreferencesActivate: function() {
Main.overview.hide();
- this._spawn(['gnome-control-center', '-o']);
+ Util.spawnDesktop('gnome-control-center');
},
_onLockScreenActivate: function() {
Main.overview.hide();
- this._spawn(['gnome-screensaver-command', '--lock']);
+ Util.spawn(['gnome-screensaver-command', '--lock']);
},
_onLoginScreenActivate: function() {
_onQuitSessionActivate: function() {
Main.overview.hide();
- this._spawn(['gnome-session-save', '--logout-dialog']);
+ Util.spawn(['gnome-session-save', '--logout-dialog']);
},
_onShutDownActivate: function() {
Main.overview.hide();
- this._spawn(['gnome-session-save', '--shutdown-dialog']);
- },
-
- _spawn: function(args) {
- // FIXME: once Shell.Process gets support for signalling
- // errors we should pop up an error dialog or something here
- // on failure
- let p = new Shell.Process({'args' : args});
- p.run();
+ Util.spawn(['gnome-session-save', '--shutdown-dialog']);
}
};
data/gnome-shell.desktop.in.in
data/org.gnome.shell.gschema.xml.in
data/org.gnome.accessibility.magnifier.gschema.xml.in
+js/misc/util.js
js/ui/appDisplay.js
js/ui/appFavorites.js
js/ui/dash.js